#ifndef PROPERTIES_H_
#define PROPERTIES_H_

#include <stdint.h>
#include <unistd.h>
#include <stdint.h>

/** the maximum length of a property key, including the trailing zero terminator */
#define PROP_NAME_MAX 32
/** the maximum length of a property value, including the trailing zero terminator */
#define PROP_VALUE_MAX 92

#ifdef __cplusplus
extern "C" {
#endif

    /**
     * set key/pair to the system property store.
     * there are 2 kinds of property:
     * - temporary property: the value is lost after system restarts.
     * - persist property: the value survives after system restarts. the key of persist key starts
     *                     with 'persist.' prefix.
     * additionally, set property operation is protected by uid permission. different uid can set
     * different properties. for details, please consult the owner of system properties service.
     * @param  key   the key of key/value pair, the string length, including the trailing zero
     *               termintor, should <= **PROP_NAME_MAX** bytes.
     * @param  value the value of key/value pair, the string length, including the trailing zero
     *               termintor, should <= **PROP_VALUE_MAX** bytes.
     * @return returns 0 if ok, negative number if failed.
     */
    int property_set(const char *key, const char *value);
    /**
     * get the value associated with the key, if not found, the provided default value is used as
     * the result.
     * @param  key           the key to find, the string length, including the trailing zero
     *                       termintor, should <= **PROP_NAME_MAX** bytes.
     * @param  value         the byte array used to return the value. the byte array should have
     *                       been allocated, the array size should >= **PROP_VALUE_MAX** bytes.
     * @param  default_value the default value, used as the result when the value is not found.
     * @return return the number of bytes in the result value, if not found and no default value
     *                provided, returns 0; returns -1 if the provided parameters is invalid.
     * @example
     *     const char *key = "persist.test.key";
     *     char value[PROP_VALUE_MAX];
     *     int result = property_get(key, value, "");
     *     if (result >= 0) printf("value %s", value);
     */
    int property_get(const char *key, char *value, const char *default_value);
    /**
     * iterate all properties in the system property store, call *propfn* function with each
     * property key/value pair.
     * @param propfn  the callback function, will be called with each property key/value pair and
     *                the extra cookie info.
     * @param cookie  the extra cookie info, will be passed to the callback function along with
     *                property key/value pair.
     * @return just returns 0 always.
     */
    int property_list(void (*propfn)(const char *key, const char *value, void *cookie), void *cookie);


    /**
     * the property changed callback function type
     * @param  key       the changed property key
     * @param  user_data the user data user passed to property_watch() api
     * @return           void
     */
    typedef void (*property_callback)(const char *key, void *user_data);
    /**
     * add property change listener for the property.
     * callback will not be called when setting a same value, as the property value not changed.
     * due to the limitation of the underlying linux inotify api, callback may be called only once
     * when successive property change occurs within a very short time, like 100ms,
     * @param  key       the property key to watch
     * @param  cb        the callback function, will be called when the property changed,
     *                   it will be called on a background thread managed by this library.
     * @param  user_data the user data, it will be passed back to the callback function,
     *                   this pointer is needed when unwatch.
     * @return           0 if ok, -1 if error
     */
    int property_watch(const char *key, property_callback cb, void *user_data);
    /**
     * remove the property change listener.
     * @param  key       the property key
     * @param  cb        the callback function used to call watch() previously.
     * @param  user_data the user data used to call watch() previously.
     * @return           0 if ok, -1 if error
     */
    int property_unwatch(const char *key, property_callback cb, void *user_data);

    /**
     * synchronize property to other core;
     * it is marked as requiring synchronization across multiple cores when this interface is called.
     * if no synchronization is required, you need to call property_unsync to cancel the synchronization.
     * @param  keys      set of property keys that need to be synchronized, property key are separated by comma.
     * @return           0 if ok, -1 if error
     * @example
     *     const char *key = "test.property.ketA,test.property.ketB";
     *     int result = property_sync(key, value, "");
     *     if (result != 0) printf("property_sync fail");
     */
    int property_sync(const char *keys);

    /**
     * cancel the synchronization of property between multiple cores.
     * @param  keys      set of properties keys to unsynchronize, property key are separated by comma.
     * @return           0 if ok, -1 if error
     * @example
     *     const char *key = "test.property.ketA,test.property.ketB";
     *     int result = property_unsync(key, value, "");
     *     if (result != 0) printf("property_unsync fail");
     */
    int property_unsync(const char *keys);

    typedef void (*property_callback_fn)(void *user_data);
    /**
     * **deprecated**, use property_watch() instead!
     * add property change listener. only 1 listener is allowed for a key, second watch on the same
     * key will fail.
     * @param  key       the key to listen
     * @param  cb        the callback function, it will be called on a background thread
     *                   managed by this library.
     * @param  user_data the extra data, it will be passed to the callback when change happens.
     * @return returns 0 if ok, -1 if error.
     */
    int property_add_watch(const char *key, property_callback_fn cb, void * user_data);
    /**
     * **deprecated**, use property_unwatch() instead!
     * remove all listeners of the key.
     * @param  key the listener of the key to remove.
     * @return returns 0 if ok, -1 if error.
     */
    int property_rm_watch(const char *key);
    /**
     * **deprecated**, use property_unwatch() instead!
     * remove all listener entries associated with the key and the callback.
     * @param  key - the key being watched
     * @param  cb  - the listener want to be removed
     * @return returns 0 if ok, -1 if error.
     */
    int property_rm_watch_by_callback(const char *key, property_callback_fn cb);

#ifdef __cplusplus
}
#endif

#endif // PROPERTIES_H_
